﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ALDIOrganizer
{
    /// <summary>
    /// Contains 0, 1 or (maximum) 2 Shifts
    /// </summary>
    /// <remarks>
    /// Used by the Cell class.
    /// An _employee can work a maximum of 2 Shifts On any particular Day
    /// (e.g. 8-12, and then come back to work 17-cl; unusual, but it can happen.)
    /// Hence any Cell in our "spreadsheet" may contain two Shifts instead of just one.
    /// The ShiftTandem class 
    /// </remarks>
    
    [Serializable]    
    public class ShiftTandem : IEnumerable, ICloneable
    {

        #region values

        private Shift _second;

        private bool InvalidValues
        {
            // id1 slot Empty, the id2 slot - no? it means there'pShift a bug and will result in an pException being thrown
            get
            {
                return _second != null && First == null;
            }
        }

        public Shift First { get; private set; }

        public Shift Second
        {
            get
            {
                if (InvalidValues)
                {
                    throw new ApplicationException("ShiftTandem._second has value while ShiftTandem._first is null!");
                }
                return _second; // if it hasn't got Value
            }
        }
        #endregion values

        #region collection management methods
        public int Count
        {
            get
            {
                if (_second != null)
                {
                    return 2;
                }
                return (First == null ? 0 : 1);
            }
        }

        public void Add(Shift s)
        {
            switch (Count)
            {
                case 2:
                    {
                        throw new ApplicationException("ShiftTandem.Add - the class is full!");
                    }
                case 1:
                    {
                        _second = s;
                        break;
                    }
                case 0:
                    {
                        First = s;
                        break;
                    }
                default:
                    {
                        break;
                    }
            }            
        }        

        public void Clear()
        {
            First = null;
            _second = null;
        }

        public Shift[] ToArray()
        {
            if (Count == 0)
            {
                return new Shift[0];
            }

            var array = new Shift[Count];
            array[0] = First;
            if (array.Length > 1)
            {
                array[1] = Second;
            }
            return array;
        }

        public void Sort()
        {
            if (Count < 2)
            {
                return; // nothing to swap
            }
            if (First.CompareTo(Second) <= 0)
            {
                return; // no need to swap
            }
            
            // swapping
            var third = (Shift)Second.Clone();
            // cloning a shift loses its Parent property
            var parentBackup = First.Parent;
            _second = (Shift)First.Clone();
            _second.Parent = parentBackup;
            First = third;
            // retrieving Parent from our temporary backup
            First.Parent = parentBackup;
        }

        public bool MarkedAsOdd
        {
            get
            {
                var isFirst = (First == null) ?
                    false :
                    First.MarkedAsOdd;
                var isSecond = (Second == null) ?
                    false :
                    Second.MarkedAsOdd;                
                return (isFirst | isSecond);
            }
        }        

        #endregion

        #region interfaces
        public IEnumerator GetEnumerator()
        {
            return new ShiftTandemEnumerator(this);
        }

        public object Clone()
        {
            return Cloner.Copy(this);
        }

        #endregion

        #region enumerator
        private class ShiftTandemEnumerator : IEnumerator
        {
            private int _position; // not -1, because we count our elements as "1st" and "2nd"
            private readonly ShiftTandem _st;

            public ShiftTandemEnumerator(ShiftTandem st)
            {
                _st = st;
            }

            public object Current
            {
                get
                {
                    if (_position == 2)
                    {
                        return _st.Second;
                    }
                    return _position == 1 ? _st.First : null;
                }
            }

            public bool MoveNext()
            {
                if (_position < _st.Count)
                {
                    _position++;
                    return true;
                }
                return false; // if we are at the Finish
            }

            public void Reset()
            {
                _position = 0;
            }

        }
        #endregion

        #region indexer
        public Shift this[int index]
        {
            get
            {
                if (index < 1) throw new IndexOutOfRangeException();
                if (index > Count) throw new IndexOutOfRangeException();

                if (index == 1) return First;
                return index == 2 ? Second : null;
            }
        }
        #endregion
    }

    
}